package com.bckj.fastboot.log;

import cn.hutool.core.util.StrUtil;
import com.bckj.fastboot.core.jackson.JsonUtils;
import com.bckj.fastboot.log.model.LogRecord;
import com.bckj.fastboot.security.model.OAuthUser;
import com.bckj.fastboot.security.util.SecurityUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

@Slf4j
@Aspect
@RequiredArgsConstructor
public class BusinessLogAspect {

    public final static int MAX_TEXT_LEN = 10000;

    private final LogProducer logProducer;

    @Around("@annotation(businessLog)")
    public Object around(ProceedingJoinPoint joinPoint, BusinessLog businessLog) throws Throwable {
        String logDescription = businessLog.value();
        int bizType = businessLog.bizType();

        // 执行目标方法
        Object result = null;
        boolean isFail = false;
        String failReason = null;
        Exception exception = null;
        try {
            result = joinPoint.proceed();
        } catch (Exception e) {
            isFail = true;
            failReason = e.getMessage();
            exception = e;
        }
        List<LogRecord> list = new ArrayList<>();
        Optional<OAuthUser> oAuthUser = SecurityUtils.getUser();
        Object[] args = joinPoint.getArgs();
        String reqContent = JsonUtils.toJsonStr(args);
        String respContent = JsonUtils.toJsonStr(result);
        try {
            //构建系统日志
            LogRecord logRecord = buildLogRecord(logDescription, bizType, reqContent, respContent, isFail, failReason);
            list.add(logRecord);
            if (exception!= null) {
                //如果有异常，则只保存系统日志
                logProducer.produce(list);
                throw exception;
            }
            List<LogRecord> logs = LogContext.getLog();
            if (logs != null) {
                for (LogRecord record : logs) {
                    record.setBizType(bizType);
                    oAuthUser.ifPresent(p -> {
                        record.setUserId(p.getId());
                        record.setUsername(p.getUsername());
                    });
                    record.setCreateTime(new Date());
                }
                list.addAll(logs);
            }
            logProducer.produce(list);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            LogContext.clear();
        }
        return result;
    }

    private LogRecord buildLogRecord(String logDescription, int bizType, String reqContent, String respContent, boolean isFail, String failReason) {
        LogRecord logRecord = new LogRecord();
        logRecord.setType(0);
        logRecord.setBizType(bizType);
        logRecord.setContent(logDescription);
        logRecord.setReqContent(StrUtil.sub(reqContent, 0, MAX_TEXT_LEN));
        logRecord.setRespContent(StrUtil.sub(respContent, 0, MAX_TEXT_LEN));
        logRecord.setIp("127.0.0.1");
        logRecord.setIsFail(isFail);
        if (failReason != null) {
            logRecord.setFailReason(StrUtil.sub(failReason, 0 ,200));
        }
        logRecord.setCreateTime(new Date());
        return logRecord;
    }
}